# _*_ coding:utf-8 _*_
# @File  : daily_profit.py
# @Time  : 2021-12-13  09:54
# @Author: zizle

import pandas as pd
import datetime
from typing import Optional

from db import FAConnection
from status import r_status
from logger import logger


def calculate_price_diff(direction, price, close_price):
    return close_price - price if (direction == '多' or direction == '平多') else price - close_price


def generate_daily_profit(handle_ts: Optional[int] = None):  # 生成每个账户的今日权益
    if handle_ts is None:
        handle_ts = int(datetime.datetime.strptime(datetime.datetime.today().strftime('%Y-%m-%d'), '%Y-%m-%d').timestamp())
    # 查询所有持仓情况
    db = FAConnection(conn_name='任务处理每日权益')
    sql = 'SELECT a.*,b.r_fund,b.b_fund ' \
          'FROM user_invest_position AS a ' \
          'INNER JOIN user_invest_account AS b ON a.account=b.account;'
    records = db.query(sql, keep_conn=True)
    if not records:
        logger.info('今日还没有任何账户持仓数据需要处理!')
        return {'code': r_status.NOT_CONTENT, 'message': '还没有数据需要处理!'}
    # 查询今日最新行情数据
    latest_sql = 'SELECT a.quotes_ts,a.contract,a.open_price,a.close_price ' \
                 'FROM dat_futures_daily_quotes AS a ' \
                 'WHERE a.quotes_ts=(SELECT MAX(quotes_ts) FROM dat_futures_daily_quotes);'
    db_conn = FAConnection(conn_name='查询持仓')
    latest_quotes = db_conn.query(latest_sql, keep_conn=True)
    # 行情数据处理成dict
    quotes_ts = latest_quotes[0]['quotes_ts']
    if handle_ts != quotes_ts:
        logger.error(f'处理日期{handle_ts}与行情日期{quotes_ts}不符合，无法生成数据!')
        db_conn.close()
        return {'code': r_status.VALIDATE_ERROR, 'message': '处理日期与行情日期不符合，无法生成数据!'}
    # 并且得等于处理的当天
    current_ts = int(datetime.datetime.strptime(datetime.datetime.today().strftime('%Y-%m-%d'), '%Y-%m-%d').timestamp())
    if current_ts != handle_ts:
        logger.error(f'处理日期{handle_ts}与当前日期{quotes_ts}不符合，无法生成数据!')
        db_conn.close()
        return {'code': r_status.VALIDATE_ERROR, 'message': '处理日期与当前日期不符合，无法生成数据!'}

    quotes_data = {f'{item["contract"]}': item["close_price"] for item in latest_quotes}

    # 查出今日的所有账户权益
    profits = db_conn.query('SELECT * FROM user_invest_profit WHERE create_ts=%s;', param=[handle_ts], keep_conn=True)
    exist_accounts = [i['account'] for i in profits]

    # 分账户，计算当前日期下，总的浮动收益和保证金占用
    df = pd.DataFrame(records)
    # 最新价
    df['quote_price'] = df['contract'].apply(lambda x: quotes_data.get(x))
    # 计算价差，计算浮动收益
    df['price_diff'] = df.apply(lambda x: calculate_price_diff(x['direction'], x['o_price'], x['quote_price']), axis=1)
    df['h_profit'] = df['price_diff'] * df['o_hands'] * df['hand_amount']
    df['bail'] = df['h_profit'] * df['bail_rate']  # TODO 保证金统计
    # 解出账户的权益数据
    account_funds = {f'{f["account"]}': f["r_fund"] for f in df.to_dict(orient='records')}
    account_bails = {f'{f["account"]}': f["b_fund"] for f in df.to_dict(orient='records')}
    # 账号分组计算浮动收益和
    account_profit_df = df.groupby(by=['account'], as_index=False)[['h_profit', 'bail']].sum()
    account_profit_df['r_fund'] = account_profit_df['account'].apply(lambda x: account_funds.get(x))
    account_profit_df['b_fund'] = account_profit_df['account'].apply(lambda x: account_bails.get(x))
    exists_obj = []
    no_exists = []
    for item in account_profit_df.to_dict(orient='records'):
        item['h_profit'] = round(item['h_profit'], 2)
        item['bail'] = round(item['bail'], 2)
        item['total_profit'] = item['r_fund']
        # item['b_fund'] = item['bail']
        item['create_ts'] = handle_ts
        if item['account'] in exist_accounts:
            exists_obj.append(item)
        else:
            item['c_profit'] = 0
            no_exists.append(item)

    # 存在的更新
    update_sql = 'UPDATE user_invest_profit ' \
                 'SET h_profit=%(h_profit)s,total_profit=%(total_profit)s ' \
                 'WHERE account=%(account)s AND create_ts=%(create_ts)s;'
    update_param = exists_obj

    # 不存在的插入
    insert_sql = 'INSERT INTO user_invest_profit (create_ts,account,h_profit,c_profit,total_profit,bail) ' \
                 'VALUES (%(create_ts)s,%(account)s,%(h_profit)s,%(c_profit)s,%(total_profit)s,%(bail)s);'
    insert_param = no_exists

    # 更新账户保证金占用
    update_account = 'UPDATE user_invest_account SET b_fund=%(b_fund)s WHERE account=%(account)s;'
    update_account_param = exists_obj + no_exists

    # 事务型处理数据
    sql_list = [update_sql, update_account]
    sql_param = [update_param, update_account_param]
    if no_exists:
        sql_list.append(insert_sql)
        sql_param.append(insert_param)

    success = db_conn.execute_tasks(sql_list=sql_list, param_list=sql_param, many=True)
    if success:
        return {'code': r_status.SUCCESS, 'message': '处理数据成功'}
    else:
        return {'code': r_status.SERVER_ERROR, 'message': '处理数据失败了!'}
